from model.user import User
from pages.internal_page import InternalPage
from pages.page import Page
from pages.login_page import LoginPage
from pages.user_management_page import UserManagementPage
from pages.user_profile_page import UserProfilePage
from pages.add_movie_page import AddMoviePage
from pages.movie_info_page import MovieInfoPage
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import *
from model.movie import Movie
import re
from selenium.webdriver.common.keys import Keys


class Application(object):
    def __init__(self, driver, base_url):
        driver.get(base_url)
        self.wait = WebDriverWait(driver, 10)
        self.page = Page(driver, base_url)
        self.login_page = LoginPage(driver, base_url)
        self.internal_page = InternalPage(driver, base_url)
        self.user_profile_page = UserProfilePage(driver, base_url)
        self.user_management_page = UserManagementPage(driver, base_url)
        self.add_movie_page = AddMoviePage(driver, base_url)
        self.movie_info_page = MovieInfoPage(driver, base_url)

        self.movie_list = None

    def logout(self):
        self.internal_page.logout_button.click()
        self.wait.until(alert_is_present()).accept()

    def ensure_logout(self):
        element = self.wait.until(presence_of_element_located((By.CSS_SELECTOR, "nav, #loginform")))
        if element.tag_name == "nav":
            self.logout()

    def login(self, user):
        lp = self.login_page
        assert lp.is_this_page
        lp.username_field.send_keys(user.username)
        lp.password_field.send_keys(user.password)
        lp.submit_button.click()

    def ensure_login_as(self, user):
        element = self.wait.until(presence_of_element_located((By.CSS_SELECTOR, "nav, #loginform")))
        if element.tag_name == "nav":
            # we are on internal page
            if self.is_logged_in_as(user):
                return
            else:
                self.logout()
        self.login(user)

    def is_logged_in(self):
        return self.internal_page.is_this_page

    def is_logged_in_as(self, user):
        return self.is_logged_in() \
            and self.get_logged_user().username == user.username

    def is_not_logged_in(self):
        return self.login_page.is_this_page

    def get_logged_user(self):
        self.internal_page.user_profile_link.click()
        upp = self.user_profile_page
        assert upp.is_this_page
        return User(username=upp.user_form.username_field.get_attribute("value"),
                    email=upp.user_form.email_field.get_attribute("value"))

    def add_user(self, user):
        self.internal_page.user_management_link.click()
        ump = self.user_management_page
        assert ump.is_this_page
        ump.user_form.username_field.send_keys(user.username)
        ump.user_form.email_field.send_keys(user.email)
        ump.user_form.password_field.send_keys(user.password)
        ump.user_form.password1_field.send_keys(user.password)
        ump.user_form.submit_button.click()

    def goto_main_page(self, forced):
        if forced or not self.internal_page.is_this_page:
            self.internal_page.refresh_button.click()

    def get_movie_list(self):
        self.goto_main_page(False)
        elements = self.get_elements((By.CSS_SELECTOR, "#results>a>.movie_box>.title"))
        self.movie_list = [name.text for name in elements]
        return self.movie_list

    def get_elements(self, locator):
        try:
            elements = self.wait.until(presence_of_all_elements_located(locator))
            return elements
        except WebDriverException:
            return []

    def add_movie(self, movie):
        self.goto_main_page(False)
        self.internal_page.add_movie_button.click()
        amp = self.add_movie_page
        assert amp.is_this_page
        amp.movie_name_field.send_keys(movie.movie_name)
        amp.movie_year_field.send_keys(movie.movie_year)
        amp.save_movie_button.click()
        assert self.movie_info_page.is_this_page
        assert self.movie_info_page.movie_title.text == movie.movie_title

    def remove_movie(self, movie_name):
        self.goto_main_page(False)
        self.internal_page.movie_button(movie_name).click()
        assert movie_name in self.movie_info_page.movie_title.text

        remove_button = self.movie_info_page.remove_movie_button
        #alert_text = re.search("\('(.+)'\)", remove_button.get_attribute('onclick')).group(1)
        remove_button.click()
        self.wait.until(alert_is_present()).accept()
        #alert = self.page.switch_to_alert()
        #assert alert.text == alert_text
        #alert.accept()
        assert self.internal_page.is_this_page

    def get_first_movie_name(self):
        if len(self.internal_page.search_field.get_attribute('value')) > 0:
            self.internal_page.clear_search_field()

        movie_list = self.get_movie_list()
        if len(movie_list) > 0:
            return movie_list[0]

        movie = Movie.random()
        self.add_movie(movie)
        self.goto_main_page(True)
        return movie.movie_name

    def find_movie(self, movie_name):
        self.goto_main_page(False)
        self.internal_page.search_field.clear()
        self.internal_page.search_field.send_keys(movie_name, Keys.ENTER)

    def verify_movie_list_incremented(self, movie_name):
        old_list = self.movie_list
        list_diff = self.__diff(self.get_movie_list(), old_list)
        assert(len(list_diff) == 1)
        assert(list_diff.pop() == movie_name)

    def verify_movie_list_decremented(self, movie_name):
        old_list = self.movie_list
        list_diff = self.__diff(old_list, self.get_movie_list())
        assert(len(list_diff) == 1)
        assert(list_diff.pop() == movie_name)

    def verify_movie_list_not_changed(self):
        old_list = self.movie_list
        new_list = self.get_movie_list()
        assert(len(self.__diff(old_list, new_list)) == 0)
        assert(len(self.__diff(new_list, old_list)) == 0)

    def __diff(self, a, b):
        b = set(b)
        return [aa for aa in a if aa not in b]